package Demo;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: DELL
 * Date: 2023-01-10
 * Time: 18:38
 */

/**
 * 实现一个标准库得阻塞队列
 */

class MyBlockingQueue {
    // Blocking Queue是一个泛型, 此处只考虑用int类简单模拟
    private int[] elme = new int[1000]; // 定义一个长度为1000得队列数组
    private int head = 0; // 头节点
    private int tail = 0; // 尾节点
    private int size = 0; // 队列有效个数

    // 入队列操作
    public void put(int value) throws InterruptedException {
        synchronized (this) {
            // 判断是否可以入队列
            while (size == elme.length) {
                // 满了阻塞等待
                this.wait(); //此处this指代捕获外界MyBlockingQueue得实例
            }
            // 入队列时, 数组前面得元素已经出队列空了位置出来,但入队列得位置已经到了最后队尾(elme[1000])
            // 因此需要考虑队列循环使用

            elme[tail] = value;
            tail++;
            //判断队尾位置是否超过1000
            if (tail >= elme.length) {
                // 让队尾指向头,开始新一轮
                tail = 0;
            }
            size++;
            this.notify(); // 唤醒take中得wait,表明有元素入队列了可以出队列了
        }
    }

    public Integer take() throws InterruptedException {
        int result = 0; // 用于接收返回值
        synchronized (this) {
            while (size == 0) {
                // 队列为空,阻塞等待
                this.wait();
            }
            result = elme[head];
            head++;
            // 同样,当出到elme[1000]位置时,前面又进来了元素,此时应该从头开始从新出
            // 实现一个闭环得循环
            if (head >= elme.length) {
                head = 0;
            }
            size--;
            this.notify(); // 唤醒put中得wait,表名有元素出队列了可以继续入队列了
        }

        return result; // 返回出队列得值给用户
    }

}

public class Thread_Demo18 {
    public static void main(String[] args) throws InterruptedException {
        /*MyBlockingQueue queue = new MyBlockingQueue();
        queue.put(1);
        queue.put(2);
        queue.put(3);
        queue.put(4);
        int result = 0;
        result = queue.take();
        System.out.println("result :" + result);
        result = queue.take();
        System.out.println("result :" + result);
        result = queue.take();
        System.out.println("result :" + result);
        result = queue.take();
        System.out.println("result :" + result);
        result = queue.take();
        System.out.println("result :" + result);*/

        // 重写生产者消费者模型
        MyBlockingQueue queue = new MyBlockingQueue();
        // 消费者线程
        Thread customer = new Thread(() -> {
            while(true) {
                //不断消耗--出队列
                try {
                    int result = queue.take();
                    System.out.println("消费: " + result);
                    Thread.sleep(500); // 消费慢一点
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        customer.start();

        Thread producer = new Thread(() -> {
            int count = 0;
            // 不断得产生 -- 入队列
            while(true) {
                try {
                    System.out.println("生产: " + count);
                    queue.put(count);
                    count++;
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        producer.start();
    }
}
